/* 
1、先来实现数据劫持，就是给对象的每个属性添加get与set，这是响应式的前提
2、实现深度劫持 无论传入的对象有没有嵌套 都需要给对应的属性添加劫持功能
3、实现数据代理，就是将传入进来的对象中的data中的值添加到vm实例对象上

*/


// 先写构造函数
function Vue(options) {
    this.$data = this._data = options.data

    //1、调用函数， 实现数据劫持，给对象的每个属性都添加一个get和set
    observe(this.$data)

    // 2、实现代理
    Object.keys(this.$data).forEach(key => {
        this.proxy(key)
    })
}

// 这个函数用于实现代理
Vue.prototype = {
    proxy: function (key) {
        // 在构造函数的原型对象的方法中，this还是指向的构造函数的实例对象
        Object.defineProperty(this, key, {
            get() {
                // 返回原来默认值
                return this.$data[key]
            },
            set(value) {
                // 修改之后新值覆盖原值
                this.$data[key] = value
            }
        })
    }
}



// 这个函数用来做数据劫持
function observe(obj) {
    //6. 判断传入的数据是否是对象,条件结束，不向下执行了,递归终止条件
    if (!obj || typeof obj !== 'object') return

    //1. 获取传入的数据，遍历传进来的数据
    Object.keys(obj).forEach(key => {

        // 3. 获取当前属性原来的值，保存到一个变量中
        let oldValue = obj[key]

        // 5.进行递归调用实现深度劫持(对象中传递对象)
        observe(oldValue)

        // 2.给每个属性添加get和set方法
        Object.defineProperty(obj, key, {

            // 4.给每个属性的get和set函数中添加代码实现劫持
            get() {
                return oldValue
            },
            set(value) {
                // 修改触发set，会被重新赋值
                oldValue = value
            }
        })
    })
}